package com.briup.bookstore.utils;

import com.briup.bookstore.common.exception.ServiceException;
import com.briup.bookstore.common.response.ResultCode;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.ExpiredJwtException;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.MalformedJwtException;
import io.jsonwebtoken.security.Keys;
import io.jsonwebtoken.security.SignatureException;
import org.springframework.util.StringUtils;

import javax.crypto.SecretKey;
import java.util.Date;
import java.util.Map;

/**
 * JWT工具类
 */
public class JwtUtil {

    private static final Long EXPIRATION_TIME = 24 * 60 * 60 * 1000L;
    private static final SecretKey SECURITY_KEY = Keys.hmacShaKeyFor(
            "asdfghjkl;ertyuioqpwxcvbnm,sdftgyhoxzcvbnmerty".getBytes());


    /**
     * 签发token
     *
     * @param claims 需要存入token中的载荷数据，如用户id等信息
     * @return token
     */
    public static String sign(Map<String, Object> claims) {
        return Jwts.builder()
                // 设置token过期时间
                .expiration(new Date(System.currentTimeMillis() + EXPIRATION_TIME))
                // 设置载荷信息
                .claims(claims)
                // 设置密钥
                .signWith(SECURITY_KEY)
                .compact();
    }

    /**
     * 解析token，并且获取到对应的claims载荷数据
     *
     * @param token token
     * @return 载荷数据
     */
    private static Object parserToken(String token) {
        return Jwts.parser()
                .verifyWith(SECURITY_KEY)
                .build()
                .parse(token)
                .getPayload();
    }

    /**
     * 根据载荷的名字获取载荷中存储的信息，
     *
     * @param claimName 载荷信息的名字，key
     * @param tClass    载荷信息所属类型的字节码对象
     * @return 载荷信息
     */
    public static <T> T getInfo(String token, String claimName, Class<T> tClass) {
        try {
            // token为空，表示未登录
            if (!StringUtils.hasText(token)) {
                throw new ServiceException(ResultCode.TOKEN_IS_MISSING);
            }
            // 解析token获取载荷对象
            Claims claims = (Claims) parserToken(token);
            // 在载荷中获取对应的数据
            return claims.get(claimName, tClass);
        } catch (ExpiredJwtException e) {
            throw new ServiceException(ResultCode.TOKEN_IS_TIMEOUT);
        } catch (MalformedJwtException | SignatureException e) {
            throw new ServiceException(ResultCode.TOKEN_IS_INVALID);
        }
    }
}